
"use strict";

function CQ() {
		this.q =  [];
}

CQ.prototype = {
	objName: 'CQ',
			
	push: function   (job){
		this.q.push(job);
	},
	pushFirst: function   (job){
		this.q.unshift(job);
	},
	pop:function () {
		return this.q.shift();
	},
	
	length: function () {
		return this.q.length;
	},

	toString: function () {
		var str = '';
		$.each( this.q, function(_,job) { str += job.name + ',';} );
		return str;
	},

	// priviliged !! 
	clear: function () {
		this.q= [];
		this.userOp_doing = false;
		this.force_stop =  false;
		this.job_doing = false;
		debug.log( this, ' cleared Q ~~~~', 'Clear flags');
	},
};




// startGM -, login,  cb.. 
function CLoginMgr() {
	var users = CDB.userdata;
	
	function getUsers() {
		return users;
	};
}

CLoginMgr.prototype = {
		objName: 'CLoginMgr: ',
	
	/*
		Start GM =============================
	*/	
		startGM:  function( username) {
			var self = this;
			debug.log(self, 'this', this, 'Strat GM ' , username);
			
			// not to will be removed cb 
			if ( ! this.resultcb ) {
				em.cbs.userlogin.add( this.resultcb = function(type, ret) { self.cbLoginRet(type, ret);} );
			}
			
			// em.tasks4user.startGM(CDB.getCurUserName());
			em.taskusr.startGM(username);
			
			// cb when cstl move done 
			em.cbs.cstlmove1done.add( self.cb_cstlmove = function( ){
				debug.log(self, 'this', this, 'cb_cstlmove in start GM  '); 
				// self.afterMove();}  );
				self.afterMove_login();}  );
		},
		
		
		// cbs 
		cbLoginRet : function( type, ret) {
			var self = this;
			debug.log(self, type, ret);
			
			// check type 
			var types = type.split(".");
			switch( types[0]) {
				
				case 'ERROR':
					debug.log(self, 'ERROR');
					if ( types[1] == 'startGM' ) {
							em.accmgr.login();
						// }
					} 
					// go next ... for sp30 
					else if ( types[1] == 'LOGIN_INFO') {
						em.cbs.userchanged.fire(-1);
					} 
					
					break;
					
				case'DATA':
					if( types[1] == 'userinfo') {
						// send info to extintor.. 
						// TODO : 여기서  exitntor 엣게 .. 정보 전달..   그대로 전달하자. 
						em.curext.update_userinfo( ret);
				}
				else if ( types[1] == 'key') {
					// update user key 
					var userinfo = CDB.getCurUserInfo();
					var newkey  = o;
					debug.log (self, 3,  ' resultLogin:: prev Key :: Store !!!!!!! ' + userinfo.key);
					userinfo.key = newkey;		// update key
					debug.log (self, 3,  ' resultLogin:: new  Key :: Store !!!!!!! ' + newkey);
					
					// set local storage
					CUtil.saveStorage('sessionkey_' +  CDB.getCurUserName() , newkey );
					// localStorage.setItem('sessionkey_' +  CDB.getCurUserName() , newkey );
					 
			 		// reflect to Query class
					CQuery.setQueryKey(newkey);


				}
				else if ( types[1] == 'server' ) {
					// update user server
					var userinfo = CDB.getCurUserInfo();
					var server  = o;
					debug.log (self, 3,  ' resultLogin:: server  ::: ' + server);
					userinfo.serverinfo.serverurl = server;		// update key
					
			 		// reflect to Query class
					CQuery.setServerurl(server);
					
					// em.infoview.show(logininfo) ;	
					
				}

			// $.extend( userinfo.castles , data.ret.user.city);
			// debug.log(self, 'process Data', o);
			break;
			case 'NOTY':
			debug.log(self, 'NOTYT', o);
			break;
		}
	},
	
		getUsersName: function() {
			var names= [] , i =0;
			var users= getUsers();
			for ( ; i < users.length; i++) {
				names.push ( users[i].name);
				}
			return names;
		},
		
			/*
			{"quest":[
		{"id":48,"grade":0,"status":0,"done":1},
		{"id":49,"grade":0,"status":1,"done":1},
	*/
		getQusetState: function( id ) {
					var userinfo = CDB.getCurUserInfo();
					debug.log (self, 3,  ' resultLogin:: questinfo  ::: '  , userinfo.questinfo);
					// find  by id
					var quest ;
					$.each ( userinfo.questinfo, function (i, el){
						 if (  el.id == id ) {
						 	quest = el ;
						 	return false; // exit each
						 }
					});
					
					return quest;
		},
		
		//  when select user:   
		// before process sequenc !!!  
		// first set user specific datas.  
		// called by controller 
		setCurUser : function(username){
			var self = this;
				// DB set,
			// set db table for this user  
			CDB.setCurUser(username);

			var keyname = 'sessionkey_' +  CDB.getCurUserName(); 
			
			var sessionkey = CUtil.getStorage(keyname);
			var userinfo = CDB.getCurUserInfo();
			if ( sessionkey ) {
				userinfo.key =  sessionkey;		// update key with storage key
				debug.log (self, 3,  ' setCurUser:: Get Stored Key ::  ' + sessionkey); 			
			} else {
				debug.log (self, 3,  ' setCurUser:: Save Key first !! ::  ' + userinfo.key);
			}
						
			// CQuery.setQueryOptions(username, userinfo.device, userinfo.droid);
			CQuery.setQueryOptions(userinfo);
			
				// server url 
			var server = userinfo.serverinfo.serverurl;		
			debug.log (self, 3,  ' setCurUser:: server  ::: ' + server);
					
			CQuery.setServerurl(server);
		},
		

		
			// func after move cstl   for start 
		afterMove_login: function() {
				var self = this;
				// get studys & update user info			
				debug.log(self, 'this', this, 'cb_cstlmove in start GM  '); 
				setTimeout( function() { self.getStudys(); } ,CUtil.RandTime(500));			
		},
		
		// for set users  ADV AR , DEF Form  
		getStudys: function() {
			var self = this;
			debug.log(self,  'this', this,'after1CstlMove :: ..get getStudys  '	);
			
			//remove cb 
			em.cbs.cstlmove1done.remove( self.cb_cstlmove );
			
			// var self = this;
			var jcb = $.Callbacks();
			
			jcb.add( function (data) {
				var studys = data.ret;
				 // {"code":0,"ret":[[1,1,1],[2,1,1],[3,0,1]],"ext":[4,4]};
				debug.log(self, 'this', this, 'got studys :', studys);
				// update solders & go next step : get heroes 
				em.cstlmgr.updateStudies(studys);
				
				// update acc info 
				var AdvAr = CDB.GetStudyLv(studys, CDB.STUDYS.ADV_ARMOR );
				CDB.setUserAdvAr(AdvAr);
				debug.log(this, 'set Adv Ar ', AdvAr);

				var DefForm = CDB.GetStudyLv(studys, CDB.STUDYS.DEF_FORMATION );
				CDB.setUserDefForm(DefForm);
				debug.log(this, 'set Def Form: ', DefForm);
				
				// fire user changed... move here for both sp30, normal  
				em.cbs.userchanged.fire();		
				 
			});
			em.tasks.getStudys(jcb);
			

		},		
		
	
		
		login: function() {
			var self = this;
			// set cb
			// var defaultuser = 'james';
			var defaultuser = '';
			// james !!! check 
			if (CDB.getCurUserName() == defaultuser ) {
				//======================= set default user ... 
				debug.log (self, 3,  ' login:: Default User .. no change session key ::  ' ); 	
				em.accmgr.setCurUser(defaultuser);
				em.infoview.setUserInfo( CDB.getCurUserInfo());
				return;
			}
			
			if ( ! this.resultcb ) {
				em.cbs.userlogin.add( this.resultcb = function(type, o) { self.resultLogin(type, o);} );		// unique check !!!  
			}
			
			em.tasks4user.processLogin(CDB.getCurUserName());
		},
	
	
		//; 각 유저별 사용할 DA array  [ 6,5,4,3, ]
		getCurDAs: function()	{
			console.log('getCurDAs ==========');
			return CDB.getUserDAsArr(CDB.getCurUser());
			
		},
		
		// user grade update : lv 
		updateGrade: function (grade){
			var userinfo = CDB.getCurUserInfo();
			userinfo.grade = grade;
			// em.infoview.updateUserinfo(grade); 	// data.ret.user 
			em.infoview.updateUserinfo('grade', userinfo); 	// data.ret.user 
			
		},

};





function CActions ( us , ext ) {
	
	// inhreit ..
	CBaseAct.call(this , ext );
	
	this.objName = 'CActions : ';
	this.force_stop =  false;

	var self = this;
	this.stage  = -1;
	this.us = us;
	
	this.ext = ext;
	
	this.Q = new CQ();
	this.actionSeq = new CActionSeq();
	
	this.stage_actions = [
		['startGM', 'dev'  ],
		['dev'  ,'enhance', 'trade', 'att' ],
		['dev'  ,'enhance',  'att' ],
	];
	this.action_map = 
	{  'startGM' :  					{ 
					cmd: 'startGM',
					doParam: { },
					cb : 			self.resultStartGM, 
					doFunc:	 self.startGM	,
				}	,
	  'login' :   self.login	,
	  
	 'dev'  :  					{ 
					cmd: 'dev',
					doParam: { },
					cb : 			self.resultDeveloping, 
					doFunc:	 self.developing	,
				}	,
	'enhance' :  self.enhance	,
	'trade' :  self.trade	,
	 'att' :  self.att	 };
	
};

CActions.prototype =  new CBaseAct();
CActions.prototype.constructor  =  CActions;

// CActions.prototype = {
	
	// ===============================
	// job :  { name:  .. , fn : .... , param: ... }
	// fn : should be return deffered. promise 
	
	
	CActions.prototype.doStage = function() {
		
		this.stage_dfd = $.Deferred();
		this.stage ++ ;
		this.makeActQ( this.stage );
		this.startAction();
		return this.stage_dfd.promise();
	};
	
	// @ seq action list 
	CActions.prototype.makeActQ = function(idx) {
		if ( idx >= this.stage_actions.length )  idx = this.stage_actions.length -1;
		var actions = this.stage_actions[idx];
		for (var i =0; i < actions.length; i++) {
			this.Q.push( this.action_map [ actions[i] ]) ;
		}
	};
	
	// @ start actino from Q..  order 
	CActions.prototype.startAction = function() {
		
		
		var actions = {
			name: 'EXT_actions',
			context: this, 
			action_table: [
				],
				done_cb:function () { 
					 },			// cb for complete action  	
		};
	
		// set actions
			var i;
		var action;
		for ( i=0; i < this.Q.length(); i++ ){
			action = this.Q.pop();
			actions.action_table.push(action	 ); 
		}
		
		this.actionSeq.setAction(actions);
		this.actionSeq.start();

	};
	
	

	// ================================
	// actions 
	
	//@ use usr tasks.. 
	CActions.prototype.startGM =    function () {
			var self = this;
			debug.log(self, 'this', this, 'Strat GM ' , this.us.name);
			
			if ( !this.loginmgr ) {
				this.loginmgr = new  CLoginMgr();
			}
			
			this.loginmgr.setCurUser(this.us.name);
			this.loginmgr.startGM(this.us.name);
	};
  
  
  CActions.prototype.resultStartGM =  function (data) {
			var self = this;
			debug.log(self, 'this', this, 'resultStartGM GM ' , data);
	}
	
	
	// @ auto growing... 
	// do bld. sty, train, donate, ... like sp30... 
	//  seq actions... 
	CActions.prototype.developing = function () {
			var self = this;
			debug.log(self, 'this', this, 'developing ' , this.us.name);
					var userinfo = CDB.getCurUserInfo();
					
		var actions = {
			name: 'developing',
			context: this, 
			action_table: [
			// try bld 
				{ 
					cmd: 'Try_bld',
					doParam: { },  
					cb : function(data) {
									debug.log ( self, ' Try bld ::', data );
									
									// space in bld slot : try more 
									if ( data.code == 0  && data.slot < 3 ) {
										outer.actionSeq.retryCurAction('Try_bld');
									} 	
									setTimeout( function() { outer.actionSeq.next.call(outer.actionSeq); } ,CUtil.RandTime(2000)); 
					},
					doFunc:	 self.tryBld,
				},	
			// try study
				{ 
					cmd: 'Try study',
					doParam: { },
					cb : function(data) {
									setTimeout( function() { outer.actionSeq.next.call(outer.actionSeq); } ,CUtil.RandTime(2000)); 
									debug.log ( self, ' Try study ::', data ); 	
						},
					doFunc:	 self.tryStudy,
				},	
				// try train  : to use h first 
				{ 
					cmd: 'Try Train',
					doParam: { 'type': 2, 'num': 5000 } , 	// disband all  
					cb : function(data) {
									debug.log ( self, ' Try Train ::', data ); 
									setTimeout( function() { outer.actionSeq.next.call(outer.actionSeq); } ,CUtil.RandTime(2000)); 
						},
					doFunc:	 self.tryTrain,
				},					
							// try donate 
				{ 
					cmd: 'Try donate',
					doParam: { },
					cb : function(data) {
									debug.log ( self, ' Try donate ::', data ); 	
									setTimeout( function() { outer.actionSeq.next.call(outer.actionSeq); } ,CUtil.RandTime(2000)); 
						},
					doFunc:	 self.tryDonate,
				}	
				],
				done_cb:function () { 
					// done step3 .. 
					// clear time 
					clearInterval( self.step3.cit_timer );
					
					// noty view 
					em.infoview.showCurIng( self.step, 'Seq Done:T last ' + self.curTrainNum );
						
					//  go next user action 
						self.dfd.resolve();
							// restart this action seq after some time. 
							// setTimeout( function() { self.step3Monitor.call( self ); } , this.cit_timeout + 5000 ); // 1 min later 
					 },			// cb for complete action  	
		};
	
		this.dev = this.dev || {};
		if ( ! this.dev.actionSeq ) this.dev.actionSeq = new CActionSeq();
		this.dev.actionSeq.setAction(actions);
		this.dev.actionSeq.start();
	}
	
	  
  CActions.prototype.resultDeveloping =  function (data) {
			var self = this;
			debug.log(self, 'this', this, 'resultDeveloping  ' , data);
	}
	
	/*
			registerCBs :function() {
		  var self = this;
		  // TODO : �댁젣 吏�썙���섎굹?? 
		  // when 1 cstl att done  : started by user cmd 
		em.cbs.autoCstlAttDone.add( function(cstlidx, ret_code) {
			console.log( '====================== cur cstl ' + cstlidx + ' done ... do nothing ');
			} );
			
			
			// add global event cb 
			em.cbs.forcestop.add ( function() { debug.log(self, 'force stop'); clearQ(); 
						self.force_stop = true;
						self.userOp_doing = false;
						self.job_doing = false;});
		}; 
	
	
		this.addJob = function(job) {
			if ( job) {
				pushFirstQ(job);
				console.log( job.name + ' added in the Q ');
			}
		}
		
	
		this.startMonitor = function() {
			var self = this;
			// do first monitor 
			debug.log( this, 'startMonitor !!!!!!!!!!! set timer ');
			this.monitorTimer =  setInterval( function() { self.doMonitor() ; } , 5 * 1000);
		};
		
		
		this.IsDoing = function() {
			return this.job_doing;
		};
		this.starUserOperation = function() {
			this.userOp_doing = true;;
		};
		this.endUserOperation = function() {
			this.userOp_doing = false;;
		};
		
		
		// main monitor timer
		// this can be called by timer 
		// or done event 
		this.doMonitor = function() {
			var self = this;
	
			if (self.force_stop ){
				console.log(' doMonitor. : forced stopped !. ');
				return;
			}
			
			console.log(' IN doMonitor.. : jobs ', q.length, QtoString());
			
	
					
			if ( this.job_doing || this.userOp_doing ) {
				debug.log( this, ' doing  --------',
					 ' userJob', this.userOp_doing  , 
						 ((this.job) ?  this.job.name + ' jobdoing' + this.job_doing  : '' ));
				return;
			}
				
			// pop job when no this.job is doing 
			this.job = popQ();
			// �ш린�� next check �ㅼ뿉 job �댁엳�ㅻ���, 
			if (this.job) {
				console.log( this.job.name + " start !!");
				
				self.job_doing = true;
				this.job.fn.call(this, this.job.param).always( function() {
						self.job_doing = false;
							console.log(' this.job end : go next ..  ', q.length, QtoString() );
						
						// set next job if no this.job
						if ( lengthQ() == 0) {
							console.log(' JOB is empty ::  put CheckNextJob ');
							em.jobmonitor.addJob( {name: 'checkNextJob', fn: self.checkNextJob, param: [] });					
						} 
	
					} )
					.done( function() {
							console.log(' donw  ..  cur Job ! ::  timer will start next job ');
						})
					.fail( function() {
						console.log(' cur job  Fail !!  ' );
						
					
					});
			} 
			
		};
	
		
		// ======================================================
		// job !!! define 
		// deffered  : 
						  //  find next avail cstl 
	  this.checkNextJob = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : checkNextJob in ', 'this', this);
	
			if ( em.curOp & em.Operation.AUTOHNT ) {
				// 1 : check next auto att is possible 
				// get next att time 
				var nextTime = em.cstlmgr.getAutoHntNextTime();
				
				em.util.print_result('Auto Att :: Next will be done after : at : ' + 
						nextTime.getHours()+':'+nextTime.getMinutes()+':'+nextTime.getSeconds() );
				
				// em.restartAttTimer = setTimeout ("em.hntmgr.startAuto()" , timeout );
				if ( nextTime.getTime() < $.now() ) {
					em.util.print_result( 'Start now job :  StartCstlHnt' + new Date() );
				
					em.jobmonitor.addJob( {name: 'StartCstlHnt', fn: em.jobmonitor.startAutoHnt, param: [] });
					dfd.resolve();
					return dfd.promise();
				} 
				
			}
				
	
			
			
			// 2 : check next hdrink job 
			if ( em.curOp & em.Operation.HDRIN ) {
				var nextTime = em.hdrinmgr.getNextCheckTime();
				
				em.util.print_result('hdrin  :: Next will be done after : at : ' + 
						nextTime.getHours()+':'+nextTime.getMinutes()+':'+nextTime.getSeconds() );
				
				// em.restartAttTimer = setTimeout ("em.hntmgr.startAuto()" , timeout );
				if ( nextTime.getTime() < $.now() ) {
					em.util.print_result( 'Start now job :  StartCstlHnt' + new Date() );
				
					em.jobmonitor.addJob( {name: 'doHDrin', fn: em.jobmonitor.doHDrin, param: [] });
					dfd.resolve();
					return dfd.promise();
				} 
			}
			
			// 2 : check next buy sp30  job 
			if ( em.curOp & em.Operation.BUYSP30 ) {
				if ( ! em.jobmonitor.sp30 ) {
					em.jobmonitor.sp30 = {};
					em.jobmonitor.sp30.checkCnt = 0;
				}
				
					em.util.print_result('SP30 :: trade cnt: : ' +  em.jobmonitor.sp30.checkCnt );
				// every  each 10 * 20sec    
				if ( em.jobmonitor.sp30.checkCnt++ > 10 ) {
					em.jobmonitor.sp30.checkCnt = 0;
					
					var tem = CDB.SP30.getTemInfo();
					em.util.print_result('SP30 :: find trade : ' + tem.server + ' sid:' + tem.sid );
	
					debug.log( em.jobmonitor, ' BUY SP30 : Tem info  : ', tem);
					
					em.jobmonitor.addJob( {name: 'BUYSP30', fn: em.jobmonitor.doBuySP30, param: tem });
					
					dfd.resolve();
					return dfd.promise();				
				}
			}
	
			// : check enhance  
			if ( em.curOp & em.Operation.ENHANCE ) {
				// after once done enhance.. 
				if (em.controller.doEnhance  && em.controller.doEnhance.nexttime ) {
					
					var nextTime = em.controller.doEnhance.nexttime;
					
					if ( nextTime == -1 ) {
						// cancel job 
						em.curOp &= ~em.Operation.ENHANCE;
						dfd.resolve();
						return dfd.promise();
					}
					em.util.print_result('ENHANCE  :: Next will be done after : at : ' + 
							nextTime.getHours()+':'+nextTime.getMinutes()+':'+nextTime.getSeconds() );
					
					// em.restartAttTimer = setTimeout ("em.hntmgr.startAuto()" , timeout );
					if ( nextTime.getTime() < $.now() ) {
						em.util.print_result( 'Start now job :  Enhance ' + new Date() );
					
						em.jobmonitor.addJob( {name: 'DoEnhance ', fn: em.jobmonitor.doEnhance, param: 'redo' });
						
						dfd.resolve();
						return dfd.promise();
					} 
				}
			}
			
			
			// each 5  min : check   mine nextdate , when near end : start hnt  
			if ( em.curOp & em.Operation.AVOID_PV ) {
	
				console.log( 'AVOID PV check', this);
				// after 5 min 
				if ( $.now()  > em.jobmonitor.avoid_pv.lastcheck + 60*1000*2  ){
					em.jobmonitor.avoid_pv.lastcheck = $.now();
					
					em.util.print_result( 'Start now job :  AVOID_PV :: start again' + CUtil.TimeToString(new Date()) );
					em.jobmonitor.addJob( {name: 'Avoid_PV', fn: em.jobmonitor.checkInterval_PVP, param: [] });
					dfd.resolve();
					return dfd.promise();
				} 
			}
			
			
			// check next dur .
			if ( em.curOp & em.Operation.DUR_PV ) {
				 // get nexttime of dur ..
				var nextTime;   
				if (! em.controller.dur) {
					nextTime = new Date($.now() - 10000);		// start right now   
				} else {
					nextTime = em.controller.dur.endtime;
				}
				
				em.util.print_result('UP DUR :: Next will be done after : at : ' + 
						nextTime.getHours()+':'+nextTime.getMinutes()+':'+nextTime.getSeconds() );
				
				// em.restartAttTimer = setTimeout ("em.hntmgr.startAuto()" , timeout );
				if ( nextTime.getTime() < $.now() ) {
					em.util.print_result( 'Start now job :  Start UP Dur' + CUtil.TimeToString(new Date()) );
				
					em.jobmonitor.addJob( {name: 'Start UpDur_PVP', fn: em.jobmonitor.UpDur_PVP, param: [] });
					dfd.resolve();
					return dfd.promise();
				} 
			}
			
				//  last ..  : sp 30 action ...  each time.   always do.
			if ( em.curOp & em.Operation.SP30ACTION ) {
						debug.log( this, ' SP30ACTION :   start .. next  : ');
				// em.restartAttTimer = setTimeout ("em.hntmgr.startAuto()" , timeout );
				
					em.jobmonitor.addJob( {name: 'SP30ACTION', fn: em.jobmonitor.doSP30Action, param: undefined });
					dfd.resolve();
					return dfd.promise();
			}
			// do next job 
			dfd.resolve();	
			  return dfd.promise();
	  };
					//  find next avail cstl 
	  this.startAutoHnt = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : startAutoHnt in ', this);
					// go start 		 		
			// test !!!  
			  em.controller.doAutoHnt (0, dfd);
			  return dfd.promise();
	  };
		
	
		// ... hdrin !! job  
		this.doHDrin =  function (cstl_idx) {
			var dfd = $.Deferred();
			console.log( 'job : doHDrin in ', this);		// this, <- object of doHDrin
	
			em.controller.doHDrin (dfd);
									return dfd.promise();
			
		};
		
		
		this.doSP30Action =  function ( arg ) {
			var dfd = $.Deferred();
			console.log( 'job : doSP30Action in '); 
	
			em.controller.doSP30Action(dfd);
					
			$.when( dfd).then ( function() {
				debug.log( this, 'Sucess in 						doSP30Action  jobmonitor ');
				}, 
				function() {
					
					debug.log( this, 'fail in 						doSP30Action  jobmonitor ');
				});
			  return dfd.promise();
			
		};
	
		this.doBuySP30 =  function ( tem ) {
			var dfd = $.Deferred();
			console.log( 'job : SP30 in ', tem); 
	
			em.controller.doBuySP30 (tem, dfd);
									return dfd.promise();
			
		};
					 //  Scan & Result  => make DA arr
	  this.searchDAsArr = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : scanDAsArr in ', this);
					// do world _ > cur user :  => make Da Array  [][][]
			  //  amd . sort  by dist from user x,y , print result 
			  if (! em.worldDA) 
				  em.worldDA = new CWorldDA();
											  var self = em.jobmonitor;	
			em.worldDA.startWorldScan()
				.done(function(){
												   debug.log( self,  ' Done !!! ');
					
					// do next job : scan 
					self.addJob( {name: 'StartCstlHnt next', fn: self.scanDAsArr, param: [] });
					dfd.resolve();
				});
									   return dfd.promise();
	  };
								 // do every 15 min 
	   this.doEnhance  = function(arg) {
			  var dfd = $.Deferred();
							console.log( 'job : doEnhance in ', this); // <= doEnhance object  
						 // go start 		 		
			  em.controller.doEnhance(arg,dfd);
			  return dfd.promise();
	  };
			  // send scout & wait endtime & get result
	  // print make array  => manual copy by user to js data file  
	  this.scanDAsArr  = function(args) {
			  var dfd = $.Deferred();
							console.log( 'job : scanDAsArr in ', this);
							   // go start 		 		
			  em.controller.doScanDAsArr(args,dfd);
			  return dfd.promise();
	  };
			   // send scout & wait endtime & get result
	  // print make array  => manual copy by user to js data file  
	  this.checkResultAddFav  = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : checkResultAddFav in ', this);
				   em.controller.checkResultAddFav(dfd);
			  return dfd.promise();
	  };
				   //  grow cstl 
	 // train,   study, build  ..  order job is defined by each user option 
	  this.growing = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : growing in ', this);
					// 1. check all cstls end time  & get shortest cstl
							  // check possible for cur att 
			  if ( _shortest_cstl.endtime < $.now() ) {
				  // 2. push job Q with cstl att cmd ( index)
				  var curidx = _shortest_cstl.index < 0 ?  0 : _shortest_cstl.index;
									  // �닿쾶 auto att  湲겹뀖  job ���꾨땲怨�  �꾩옱  �⑥닔媛�job �대땲源�,   洹몃깷 �섑뻾 �섎㈃ �� 
				  // pushQ ( {name: 'AutoHntAtt' + curidx ,  fn : em.controller.doAutoHnt , param: [curidx, dfd] }  );
				  em.controller.doAutoHnt (curidx, dfd);
								  }
			  //  put  job for next checking 
			   else {
				 pushQ ( { name: 'Check HntAtt', fn : em.jobmonitor.checkNextAtt , param: [] }  ); 	
				 dfd.resolve();		// go next job 
			  }
			  return dfd.promise();
	  };
																				this.UserVScan_PVP = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : UserVScan_PVP in ', this);
	
			em.worldDA.scanWorldVictom_PVP()
				.done(function(){
					debug.log( self,  'scanWorldVictom_PVP Done !!! ');
					dfd.resolve();
					
					em.cstlview.showUsPanel();
				})
				.fail(function(){
					debug.log( self,  'scanWorldVictom_PVP Fail !!! ');
					dfd.reject();
				});  	
									return dfd.promise();
	  };
			   this.lootUs_PVP = function(args) {
			  var dfd = $.Deferred();
	
			console.log( 'job : lootUs_PVP in ', this);		// this, <- object of lootUs_PVP
	
			// start before 10 sec 
			
			var timediff =  args[0].nextdate.getTime() - $.now();
			
			console.log( 'time: diff ', timediff, ' us time',  CUtil.TimeToString(args[0].nextdate) 
							, ' now ', CUtil.TimeToString(new Date()));
			
			if ( timediff > 4 * 1000 ) {
				setTimeout( function() { em.controller.doLootUs_PVP(args, dfd); } , timediff - 4*1000  );
			} else if ( timediff < - 3*60*10000  || timediff > 15 * 60 * 1000 ) {
				// invalid time.
				debug.log(this, ' time is invalid or passed' , timediff, $.now() , args[0].nextdate ) ;
				dfd.reject();
			} else {
				// start right now
				console.log( 'job : lootUs_PVP in  -- start Right now '); 
				em.controller.doLootUs_PVP (args, dfd);
			}
									return dfd.promise();
	  };
			   this.UpDur_PVP = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : lootUs_PVP in ', this);
	
			em.controller.UpDur_PVP(dfd);
									return dfd.promise();
	  };
			   this.checkInterval_PVP = function() {
			  var dfd = $.Deferred();
	
			console.log( 'job : checkInterval_PVP in ', em.jobmonitor);
	
			// craete check timer 
			if ( ! em.jobmonitor.avoid_pv ) { 
					em.jobmonitor.avoid_pv = {} ;
					em.jobmonitor.avoid_pv.lastcheck = $.now();
					}
					
			em.controller.checkInterval_PVP(dfd);
									return dfd.promise();
	  },
										*/
	

	
